import { computed, ref } from "vue";
import CryptoJS from "crypto-js";

//讯飞官网获获取 apiKey、apiSecret、app_id 等信息

const apiKey = "6a1dc26db1eec9d2799b48595a920f94";
const apiSecret = "YmYzOTk3NjMxNjc4MjBiMjU4MzUyNzNk";
const app_id = "5b13f533";

/**
 * 获取websocket url
 */
function getWebSocketUrl() {
  const url = "wss://iat-api.xfyun.cn/v2/iat";
  const host = "iat-api.xfyun.cn";
  const date = new Date().toUTCString();
  const signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`;
  const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
  const signature = CryptoJS.enc.Base64.stringify(signatureSha);
  const authorizationOrigin = `api_key="${apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`;
  const authorization = btoa(authorizationOrigin);
  return `${url}?authorization=${authorization}&date=${date}&host=${host}`;
}

/**
 * 将音频二进制数据转换为base64编码
 * @param buffer
 * @returns {string}
 */
function bufferToBase64(buffer) {
  let binary = "";
  const bytes = new Uint8Array(buffer);
  const len = bytes.byteLength;
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return window.btoa(binary);
}

// 合并多段 Int16 PCM 为单段
function concatInt16Arrays(buffers) {
  const totalLength = buffers.reduce(
    (sum, buf) => sum + new Int16Array(buf).length,
    0
  );
  const result = new Int16Array(totalLength);
  let offset = 0;
  for (const buf of buffers) {
    const arr = new Int16Array(buf);
    result.set(arr, offset);
    offset += arr.length;
  }
  return result;
}

// 将 Int16 PCM 编码为 WAV Blob（单声道 16kHz 16bit）
function encodeWavFromInt16(
  int16Samples,
  sampleRate = 16000,
  numChannels = 1,
  bitsPerSample = 16
) {
  const bytesPerSample = bitsPerSample / 8;
  const blockAlign = numChannels * bytesPerSample;
  const byteRate = sampleRate * blockAlign;
  const dataSize = int16Samples.length * bytesPerSample;
  const buffer = new ArrayBuffer(44 + dataSize);
  const view = new DataView(buffer);

  // RIFF header
  writeString(view, 0, "RIFF");
  view.setUint32(4, 36 + dataSize, true);
  writeString(view, 8, "WAVE");

  // fmt chunk
  writeString(view, 12, "fmt ");
  view.setUint32(16, 16, true); // Subchunk1Size (16 for PCM)
  view.setUint16(20, 1, true); // AudioFormat (1=PCM)
  view.setUint16(22, numChannels, true);
  view.setUint32(24, sampleRate, true);
  view.setUint32(28, byteRate, true);
  view.setUint16(32, blockAlign, true);
  view.setUint16(34, bitsPerSample, true);

  // data chunk
  writeString(view, 36, "data");
  view.setUint32(40, dataSize, true);

  // PCM data (little-endian int16)
  let offset = 44;
  for (let i = 0; i < int16Samples.length; i++, offset += 2) {
    view.setInt16(offset, int16Samples[i], true);
  }

  return new Blob([view], { type: "audio/wav" });
}

function writeString(view, offset, string) {
  for (let i = 0; i < string.length; i++) {
    view.setUint8(offset + i, string.charCodeAt(i));
  }
}

export function useXfAsr() {
  const resultText = ref(); // 识别结果
  let resultTextTemp = "";
  let iatWS = null; // websocket
  let countdownInterval = null; // 倒计时
  const nextTime = ref(60); // 录音时长（最大60秒）
  const recorder = new RecorderManager("/asr-sdk");
  const recordStatus = ref("CLOSED"); //  CONNECTING | OPEN | CLOSING | CLOSED
  const recordText = computed(() => {
    if (recordStatus.value === "CONNECTING") {
      return "建立连接中";
    } else if (recordStatus.value === "OPEN") {
      return `录音中(${nextTime.value})`;
    } else if (recordStatus.value === "CLOSING") {
      return "关闭连接中";
    } else if (recordStatus.value === "CLOSED") {
      return "开始录音";
    }
  });

  // 最近一次录音产物
  const recordedAudioBlob = ref(null); // WAV Blob
  const recordedAudioUrl = ref(""); // createObjectURL

  /**
   * 录音开始事件
   */
  recorder.onStart = () => {
    updateStatus("OPEN");
  };
  /**
   * 监听已录制完指定帧大小的文件事件。如果设置了 frameSize，则会回调此事件。
   * @param isLastFrame 当前帧是否正常录音结束前的最后一帧
   * @param frameBuffer 录音分片数据
   */
  recorder.onFrameRecorded = ({ isLastFrame, frameBuffer }) => {
    if (iatWS.readyState === iatWS.OPEN) {
      const data = {
        data: {
          // 0 :第一帧音频、1 :中间的音频、2 :最后一帧音频，最后一帧必须要发送
          status: isLastFrame ? 2 : 1,
          format: "audio/L16;rate=16000",
          encoding: "raw",
          audio: bufferToBase64(frameBuffer)
        }
      };
      iatWS.send(JSON.stringify(data));
      if (isLastFrame) {
        updateStatus("CLOSING");
      }
    }
  };
  /**
   * 录音结束事件
   * SDK 会在最后一帧回调时调用 onStop(audioBuffers)
   */
  recorder.onStop = (audioBuffers = []) => {
    clearInterval(countdownInterval);
    try {
      if (audioBuffers && audioBuffers.length) {
        const int16 = concatInt16Arrays(audioBuffers);
        const wavBlob = encodeWavFromInt16(int16, 16000, 1, 16);
        recordedAudioBlob.value = wavBlob;
        if (recordedAudioUrl.value) URL.revokeObjectURL(recordedAudioUrl.value);
        recordedAudioUrl.value = URL.createObjectURL(wavBlob);
      }
    } catch (err) {
      console.error("生成录音音频失败", err);
    }
  };

  /**
   * 倒计时
   */
  function countdown() {
    nextTime.value = 60;
    countdownInterval = setInterval(() => {
      nextTime.value--;
      if (nextTime.value <= 0) {
        clearInterval(countdownInterval);
        recorder.stop();
      }
    }, 1000);
  }

  /**
   * 更新状态
   * @param status CONNECTING | OPEN | CLOSING | CLOSED
   */
  function updateStatus(status) {
    recordStatus.value = status;
    if (status === "OPEN") {
      countdown();
    } else if (status === "CONNECTING") {
      resultText.value = "";
      resultTextTemp = "";
    }
  }

  /**
   * 渲染识别结果
   * @param resultData
   */
  function renderResult(resultData) {
    let jsonData = JSON.parse(resultData);
    console.log("识别结果：", jsonData);
    if (jsonData.data && jsonData.data.result) {
      let data = jsonData.data.result;
      let str = "";
      let ws = data.ws;
      for (let i = 0; i < ws.length; i++) {
        str = str + ws[i].cw[0].w;
      }
      // 开启 wpgs 会有此字段(前提：在控制台开通动态修正功能)
      // 取值为 "apd"时表示该片结果是追加到前面的最终结果；取值为"rpl" 时表示替换前面的部分结果，替换范围为rg字段
      if (data.pgs) {
        if (data.pgs === "apd") {
          // 将resultTextTemp同步给resultText
          resultText.value = resultTextTemp;
        }
        // 将结果存储在resultTextTemp中
        resultTextTemp = resultText.value + str;
      } else {
        resultText.value = resultText.value + str;
      }
    }
    if (jsonData.code === 0 && jsonData.data.status === 2) {
      iatWS.close();
    }
    if (jsonData.code !== 0) {
      iatWS.close();
      console.error(jsonData);
    }
  }

  /**
   * 开始录音
   */
  function startRecording() {
    if (recordStatus.value !== "CLOSED") return;
    const url = getWebSocketUrl();
    if ("WebSocket" in window) {
      iatWS = new WebSocket(url);
    } else if ("MozWebSocket" in window) {
      iatWS = new MozWebSocket(url);
    } else {
      console.error(new Error("浏览器不支持WebSocket"));
      return;
    }
    updateStatus("CONNECTING");
    iatWS.onopen = () => {
      recorder.start({ sampleRate: 16000, frameSize: 1280 });
      const params = {
        common: { app_id },
        business: {
          language: "zh_cn",
          domain: "iat",
          accent: "mandarin",
          vad_eos: 5000,
          dwa: "wpgs"
        },
        data: { status: 0, format: "audio/L16;rate=16000", encoding: "raw" }
      };
      iatWS.send(JSON.stringify(params));
    };
    iatWS.onmessage = e => {
      renderResult(e.data);
    };
    iatWS.onerror = () => {
      recorder.stop();
      updateStatus("CLOSED");
    };
    iatWS.onclose = () => {
      recorder.stop();
      updateStatus("CLOSED");
    };
  }

  /**
   * 停止录音
   */
  function stopRecording() {
    recorder.stop();
  }

  // 对外提供获取最近一次录音音频的方法
  function getRecordedAudio() {
    return {
      blob: recordedAudioBlob.value, // WAV Blob，可用于上传
      url: recordedAudioUrl.value // 可直接用于 audio 播放
    };
  }

  return {
    resultText,
    recordText,
    startRecording,
    stopRecording,
    recordedAudioBlob,
    recordedAudioUrl,
    getRecordedAudio
  };
}
